"""
Выкладка вакансий с rabota.ru в строчные объявления в газету
"""

import os
import sys
import logging                                                                  # запись логов
import re                                                                       # регулярные выражения
import sqlite3
from datetime import date

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

sys.path.append('c:\PyLib')
# from сonnsql import *
from WebKit import *


def main():

    global window
    global conn, query
    global rubrics
    global mobil_moscau

    app = QApplication(sys.argv)

    # ПОДГОТОВИТЕЛЬНЫЕ ОПЕРАЦИИ
    # Инициализация лог файла. Создаём рабочие папки.

    logging.basicConfig(filename='log.txt',level=logging.DEBUG,
        format = u'%(filename)s[LINE:%(lineno)d]# %(levelname)-8s %(message)s')

    if not os.path.exists('cookies'):
        os.makedirs('cookies')
    if not os.path.exists('data'):
        os.makedirs('data')
    if not os.path.exists('outfile'):
        os.makedirs('outfile')

    # СОЗДАНИЕ БД

    conn = sqlite3.connect("data\\rabota.db",
            isolation_level = None)
    
    conn.row_factory = sqlite3.Row                                              # для доступа с полям по имени
    query = conn.cursor()
    query.execute("CREATE TABLE IF NOT EXISTS vacant "
        "(id_vacant TEXT DEFAULT '',id_user TEXT DEFAULT '', id_org TEXT DEFAULT '',"
        "rubr TEXT DEFAULT '', prof TEXT DEFAULT '', salary TEXT DEFAULT '',"
        "face TEXT DEFAULT '', phone TEXT DEFAULT '',"
        "email TEXT DEFAULT '', moscau INTEGER DEFAULT 0,"
        "descript TEXT DEFAULT '', needs TEXT DEFAULT '', debug TEXT DEFAULT '');")

    query.execute("CREATE TABLE IF NOT EXISTS org "
        "(id_user TEXT DEFAULT '');")

    # ЧИТАЕМ СЛОВАРЬ РУБРИК. 
    """ Формат строки: регулярное выражение$номер рубрики. Читаем словарь и 
    сортируем по длинне регулярного выражения в обратном порядке."""
    with open("rubric_dict.txt",'r') as f_in:
        line = f_in.readlines()
    sort_text = sorted(line, key=len, reverse=True)
    """ Создаём список: [[скомпилированное выражение, рубрика], ...]  """
    pattern_dict = re.compile(r'(.*)\$(.*)')
    rubrics = []
    for line in sort_text:
        me = pattern_dict.search(line)
        if me:
            try:
                rubrics.append([re.compile(me.group(1)),me.group(2)])
            except re.error:
                logging.error('Ошибка регулярного выражения словаря рубрик: [{}]'.format(line))
                QMessageBox.critical(None, "КРИТИЧЕСКАЯ ОШИБКА",
                    "Подробности в файле log.txt.")
                quit()
        else:
            logging.error('Ошибка парсинга словаря рубрик: [{}]'.format(line))
            QMessageBox.critical(None, "КРИТИЧЕСКАЯ ОШИБКА",
                "Подробности в файле log.txt.")
            quit()

    # ЧИТАЕМ МАССИВ МОСКОВСКИХ ТЕЛЕФОНОВ
    """ Формат строки: от номера$до номера."""
    pattern_dict = re.compile(r'(.*)\$(.*)')                                    
    mobil_moscau = []
    with open("mobil_moscau.txt",'r') as f_in:                                  
        for sline in f_in:                                                      
            me = pattern_dict.search(sline)
            if me:
                mobil_moscau.append([me.group(1),me.group(2)])
            else:
                logging.error('Ошибка списка телефонов: {}'.format(sline))
                btn_quit_click()

    window = MainWindow()                                                       # создаем окно
    window.setWindowTitle("Выгрузка вакансий из админки rabota.ru в газету")
    window.setWindowIcon(QIcon('Help.png'))
    window.resize(1000, 700)
    window.show()                                                               # Отображаем окно
    sys.exit(app.exec_())                                                       # Запускаем цикл обработки событий


class MainWindow(QWidget):
    """
    В процессе исполнения кода все виджеты формы создаются как локальные переменные.
    Затем закладываются в контейнеры виждеты. Вся итоговая структура локальных
    сохраняется оператором self.setLayout(vbox). Чтобы иметь доступ к элементам
    класса, используем self там, где необходимо.
    """

    def __init__(self, parent=None):
        super().__init__()                                                      # запускаем init родительского класса

        self.ui()

    def ui(self):

        """ Поле со списком - название городов для логина."""
        self.sity = QComboBox()
        self.sity.addItems(['САМАРА','ТОЛЬЯТТИ'])
        """ Все кнопки кроме ЛОГИН и ВЫХОД выключаем."""
        self.btn_login = QPushButton("ЛОГИН")
        self.btn_login.clicked.connect(btn_login_click)
        self.btn_load = QPushButton("СОБРАТЬ ВАКАНСИИ")
        self.btn_load.clicked.connect(btn_load_click)
        self.btn_load.setEnabled(False)
        self.btn_org = QPushButton("ID ОРГАНИЗАЦИИ")
        self.btn_org.clicked.connect(btn_org)
        self.btn_unload = QPushButton("ВЫГРУЖАЕМ")
        self.btn_unload.clicked.connect(btn_unload_click)
        # self.btn_unload.setEnabled(False)
        self.btn_quit = QPushButton("ВЫХОД")
        self.btn_quit.clicked.connect(btn_quit_click)

        # СБОРКА ---------------------------------------------------------------
        """ В горизонтальный бокс гузим поле со списком и кнопки."""
        hbox = QHBoxLayout()
        hbox.addWidget(self.sity)
        hbox.addWidget(self.btn_login)
        hbox.addWidget(self.btn_load)
        hbox.addWidget(self.btn_org)
        hbox.addWidget(self.btn_unload)
        hbox.addWidget(self.btn_quit)
        hbox.addStretch()                                                       # "затычка" за кнопками

        """ Вертикальный бокс."""
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        """ В текстовом поле показываем текущий url. В окне боаузера логонимся."""
        self.url = QTextEdit()
        self.web = Browser()
        vbox.addWidget(self.url)
        vbox.addWidget(self.web)

        self.setLayout(vbox)


# ШАБЛОНЫ

pattern_teg = re.compile(r'<.*?>')                                              # тэги


cookies =  {'САМАРА':   'cookies\\sam.txt',                                     # хранилище куков для каждого города
            'ТОЛЬЯТТИ': 'cookies\\tol.txt'}


def btn_login_click():
    """
    Логонимся на сайте.
    """

    def cookies_load(file_name):

        # ГРУЗИМ КУКИ
        # Если файл имеется, то парсим куки и грузим в браузер.

        if os.path.exists(file_name):
            with open(file_name,'r') as f:
                allC = tuple(cooky for li in f
                    for cooky in QNetworkCookie.parseCookies(li.rstrip()))
            if allC:
                window.web.Сookies.setAllCookies(allC)

    # ЛОГИН
    # Сначала грузим куки. Потм грузим стартовую станицу. Если куки не устарели
    # происходит автологин. Если устарели пользователь логонится.

    cookies_load(cookies[window.sity.currentText()])                            # грузим куки
    window.web.get('https://www.rabota.ru/admin/')

    # ОТ ДУРАКА
    # Город и логин отключаем. Загрузку вулючаем.

    window.sity.setEnabled(False)                                               #
    window.btn_login.setEnabled(False)
    window.btn_load.setEnabled(True)



codes_html = {"</li>":"$", "<br />":"$", "<br>":"$", "\\":"/"}

codes_spec = {
    "&quot;":'"', "&amp;":"&", "&lt;":"<", "&gt;":">", "&nbsp;":" ",
    "&iexcl;":"¡", "&cent;":"¢", "&euro;":"€", "&pound;":"£", "&curren;":"¤",
    "&yen;":"¥", "&brvbar;":"¦", "&sect;":"§", "&uml;":"¨", "&copy;":"©",
    "&trade;":"™", "&laquo;":"«", "&not;":"¬", "&reg;":"®", "&macr;":"¯",
    "&deg;":"°", "&plusmn;":"±", "&times;":"×", "&divide;":"÷", "&sup2;":"²",
    "&sup3;":"³", "&acute;":"´", "&fnof;":"ƒ", "&micro;":"µ", "&para;":"¶",
    "&middot;":"·", "&cedil;":"¸", "&sup1;":"¹", "&ordm;":"º", "&ordf;":"ª",
    "&raquo;":"»", "&frac14;":"¼", "&frac12;":"½", "&frac34;":"¾", "&iquest;":"¿",
    "&larr;":"←", "&uarr;":"↑", "&rarr;":"→", "&darr;":"↓", "&harr;":"↔",
    "&spades;":"♠", "&clubs;":"♣", "&hearts;":"♥", "&diams;":"♦", "&ne;":"≠",
    "&loz;":"◊", "&circ;":"ˆ", "&tilde;":"˜	", "&bull;":"•", "&hellip;":"…",
    "&prime;":"′", "&Prime;":'″', "&oline;":"‾", "&frasl;":"⁄", "&ndash;":"–",
    "&mdash;":"—", "&lsquo;":"‘", "&rsquo;":"’", "&sbquo;":"‚", "&ldquo;":"“",
    "&rdquo;":"”", "&bdquo;":"„", "&rho;":"р"}


def btn_load_click():
    """
    Собирает ссылки на вакансии с сайта и вставляет в таблицу vacant.
    """

    stat_moscau = ['495', '499', '496', '498']

    def phone_moscau(phones):
        """
        """
        phones = ''.join(filter(lambda x: x.isalnum() or x == ',', phones))     # оставляем буквы, цыфры, запятые
        phones = phones.strip(',').split(',')                                   # убрать последнюю запятую и создать список

        for i, phone in enumerate(phones):                                      # пошли по списку телефонов
            p = phone.find('до')                                                # если есть слова "доп.", "доб." и т.д.
            if p != -1:                                                         # убираем
                phone = phone[:p]
            if len(phone)>=11:                                                  # убрать код страны (урезать до 10 цифр)
                phone = phone[1:]
            if phone[:3] in stat_moscau:                                        # стационарный московский ?
                return(1)                                                       # да
            for mobil in mobil_moscau:
                if  mobil[0] <= phone <= mobil[1]:                              # мобильный московский ?
                    return(1)                                                   # да
        return(0)                                                               # не московский телефон


    def separation_needs(descript):
        """
        Выделение требований из описания вакансии.
        """

        if not descript:                                                        # Нет исходных данных.
            return ''

        match = pattern_needs.search(descript)                                  # Ищем раздел "Требования" в описании вакансии
        if match:
            needs = match.group(2)
        else:
            return ''

        needs = needs.replace("\n"," ")                                         # Удалем из html кода переносы строк.
        for code in codes_html:                                                 # Заменяем html теги на их символьные эквиваленты.
            needs = needs.replace(code,codes_html[code])
        for code in codes_spec:                                                 # Заменяем специальные символы html на их символьные эквиваленты.
            needs = needs.replace(code,codes_spec[code])
        needs = pattern_teg.sub('', needs)                                      # Убираем все остальные теги.
        needs = needs.strip(" $")                                               # Чтобы пустых фраз не было
        phrase = needs.split('$')                                               # Разбиваем на фразы.

        phrase = phrase[0:3]                                                    # Урезаем список требования до трёх строк

        for i, item in enumerate(phrase):                                       # чистим фразы
            phrase[i] = phrase[i].strip(" -,‚.;:!•")                             # Удалем знаки препинания в конце и вначале.
            phrase[i] = phrase[i][0:1].lower() + phrase[i][1:]                  # первое слово с маленькой буквы
        needs = "; ".join(phrase)                                               # Соединяем фразы в единое предложение через ;
        if len(needs) > 500:                                                    # Слишком обширные требования.
            return('')
        return("Требования: {}.".format(needs))

    # РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ

    pattern_page = re.compile('Результаты поиска вакансий \(([\d]+?)-([\d]+?) ')# Интервал номеров вакансий
    pattern_id_vacant = re.compile('id_предложения ([\d]+?),')                  # id вакансии
    pattern_id_user = re.compile('id_пользователя ([\d]+?),')                   # id работодателя
    pattern_prof = re.compile('\t([ \S]+?)\t+?([ \S]+?)\t')                     # профессия
    pattern_face = re.compile(
        '<b>Работодатель:</b></td><td width="80%">([ \S]+?)\t')                 # контактное лицо
    pattern_org = re.compile(
        '<div class="VacancyView_location">'
        '(.+?)<span class="h_color_gray VacancyView_town">',re.S)               # название компании
    pattern_org2 = re.compile('>(.+?)<')                                        # организация внутри html ссылки
    pattern_phone = re.compile('class="phoneItem">(.+?)E-mail:</b></td>',re.S)  # телефон
    pattern_email = re.compile('E-mail:</b></td>.+?>(.+?)<',re.S)               # E-mail
    pattern_descript = re.compile(
        '<b>Образование:</b>(.+?)<b>Платная модель:</b>',re.S)                  # требования
    # pattern_needs = re.compile('(ребования:|ребование:)(.+?)</ul>',re.S)                          # требования
    pattern_needs = re.compile('(ребования:|ребование:)(.+?)(</ul>|</tr>)',re.S)# требования
    pattern_watch = re.compile('(вахт|Вахт)(.+?)(</ul>|</tr>)',re.S)            # вахта
    pattern_punct_end = re.compile('^\W*?(\w.+?)\W*?$')                         # пунтуация в конце предложения.

    # ОЧИСТКА БД

    query = conn.cursor()
    query.executescript("DELETE FROM vacant; VACUUM;")

    # ЧТЕНИЕ ВАКАНСИЙ (цикл по всем страницам)
    # В "админке" позиционирование происходит по смещению от начала списка.
    # В отладочном начально смещение делаем близко к посленей вакании.
    # Делаем бесконечный цикл. Выдем по break.

    offset = 0
    while 1:

        # ЗАГРУЗКА СТРАНИЦЫ
        # Формируем URL. Показываем в текстовом поле для контроля. Грузим.

        url = 'https://www.rabota.ru/admin/index.php?area=v3_base&action=search&sort=salary_asc&per_page=20&sourceAll=on&type=1&filter=nospam&so=f&ch=t&pub=t&se=t&wa=f&is_all_rubric=on&is_all_city=on&offset={}'.format(offset)
        window.url.setText('{}'.format(url))
        window.web.get(url)

        # ПРОВЕРКА "УДАЧНОЙ" ЗАГЗУЗКИ
        # Если id вакансии найдено, то страница вакансий загружена.

        if pattern_id_vacant.search(window.web.html):
        
            # ПОИСК ГРАНИЦ ВАКАНСИЙ
            # Вычисляем начальную и конечную позицию для поиска для каждой вакансии,
            # чтобы процедура поиска не залезала в соседнюю вакансию. Границы определяем
            # от id до id. Для последней вакансии конечная граница - конец кода.

            pos = ([m.start() for m in
                re.finditer("id_предложения", window.web.html)])
            pos.append(len(window.web.html) - 1)

            for i in range(len(pos)-1):

                # ID ВАКАНСИИ
                match = pattern_id_vacant.search(window.web.html, pos[i], pos[i+1])
                id_vacant = match.group(1).strip()

                # ID КЛИЕНТА
                match = pattern_id_user.search(window.web.html, pos[i], pos[i+1])
                id_user = match.group(1).strip()

                # ПРОФЕССИЯ
                """ Удаляем пробелы вокруг. Заменяем спецсимволы html. Заменяем 
                обраный слешь на прямой. Делаем профессию с заглавной буквы 
                для правильного поиска рубрик."""
                match = pattern_prof.search(window.web.html, pos[i], pos[i+1])
                prof = match.group(1).strip()
                for code in codes_spec:
                    prof = prof.replace(code,codes_spec[code])
                prof = prof.replace("\\", "/")    
                prof = prof[0:1].upper() + prof[1:]

                # ЗАПЛАТА

                salary = match.group(2).strip()

                # ПРИСВАИВАЕМ РУБРИКУ (по названию професии)
                # Итерация списка рубрик. Каждый элемент списка - массив двух элементов:
                # ссылка на откомпилированное регулярное выражение и номер рубрики.
                # Ищем регулярное выражение в названии профессии. Если найдено, то
                # присваиваем рубрику и заканчиваем поиск.

                rubr = 0
                for index, rubric in enumerate(rubrics):
                    if rubric[0].search(prof):
                        rubr = rubric[1]
                        debug = index + 1
                        break

                # КОНТАКТНОЕ ЛИЦО.
                # Звездочки, пропущеные имя, фамилия или отчество обрезаем.

                face = ''
                match = pattern_face.search(window.web.html, pos[i], pos[i+1])
                if match:
                    face = match.group(1).strip('*')

                # ТЕЛЕФОН.
                # Если номеров несколько, то внутри строки попадаются html теги
                # и непечатные символы. Теги убираем с помощью регулярнных выражений.
                # Непечатные символы удаляем по коду. Пробелы оставляем.
                # Если встречаются московские телефоны, изменяем рубрику на
                # "РАБОТА В МОСКВЕ"

                phone = ''
                match = pattern_phone.search(window.web.html, pos[i], pos[i+1])
                if match:
                    phone = pattern_teg.sub('', match.group(1))
                    phone = ''.join(c for c in phone if ord(c) > 31)
                    if phone_moscau(phone):
                        rubr = 900

                # ЭЛЕКТРОННАЯ ПОЧТА.

                email = ''
                match = pattern_email.search(window.web.html, pos[i], pos[i+1])
                if match:
                    email = match.group(1)

                # ОПИСАНИЕ ВАКАНСИИ
                # Вытаскиваем полное описание вакансии. Если встречается слово
                # 'вахта', то изменяем рубрику на "РАБОТА ВАХТОВЫМ МЕТОДОМ"

                descript = ''
                match = pattern_descript.search(window.web.html, pos[i], pos[i+1])
                descript = match.group(1)
                descript = ''.join(c for c in descript if ord(c) >= 32)         # удаляем непечатные символы
                if (prof.lower().find('вахт') != -1) or \
                    (descript.lower().find('вахт') != -1):
                    rubr = 500

                # ТРЕБОВАНИЯ (см. функцию)

                needs = separation_needs(descript)

                # ЗАПИСЬ В БД
                # Ошибка в процесс записи считаем фатальной.

                sql = ("INSERT INTO vacant (id_vacant, id_user, "
                    "rubr, prof, salary, face, phone, email, descript, needs, debug)"
                    " VALUES ('{}','{}','{}','{}','{}','{}','{}',"
                    "'{}','{}','{}','{}');".
                    format(id_vacant, id_user, rubr, prof, salary, face,
                    phone, email, descript, needs, debug))
                try:
                    query.execute(sql)
                    conn.commit()
                except sqlite3.Error as e:
                    logging.critical('btn_collect_ref_click: {} {}'.
                        format( e.args[0],sql))
                    btn_quit_click()
        else:                                                                   # Вакансий больше нет,
            break                                                               # поэтому выходим из бесконечного цикла.
        offset += 20                                                            # Смещаемся на следующие 20 вакансий.

    query.close()

    # ОТ ДУРАКА
    # Гасим загрузку. Включаем выгрузку.

    window.btn_load.setEnabled(False)
    window.btn_unload.setEnabled(True)

def btn_org():

    """ ПОИСК ID КОМПАНИИ 
    --- Шаблон для поиска.
    --- Курсоры для чтения и записи.
    --- Сброс индикатора процесса. В каждой записи читаем id пользователя. 
    --- Загружаем страницу [Информация о пользователе]
    --- Сдвигаем индикатор процесса.
    --- Ищем id компании и пишем в таблицу. """
    
    pattern_id_org = re.compile('company_id=([\d]+?)</a>')                       
    
    select = conn.cursor()
    update = conn.cursor()
    
    select.execute("SELECT ROWID, id_user FROM vacant;")                            # запрос по всем записям таблицы
    for ROWID, id_user in select:                                                      
        url = ('https://www.rabota.ru/admin/?area=v3_editPerson&id={}'
            .format(id_user))
        window.url.setText(url)
        window.web.get(url)

        html = window.web.html
    
        m = pattern_id_org.search(html)                                       # ищем контактное лицо
        sql = ("UPDATE vacant SET id_org = '{}' WHERE ROWID = {}".
            format(m.group(1), ROWID))
        print(sql)
        try:
            update.execute(sql) 
        except sqlite3.Error as e:
            logging.error('btn_load_vacant_click: {} {}'.format( e.args[0],sql))
            QMessageBox.critical(None, "КРИТИЧЕСКАЯ ОШИБКА", "Подробности в файле log.txt.")
            quit()        

    select.close()
    update.close()


def btn_unload_click():
    """
    """
    rub_dict = {
            '11': 'ФИНАНСЫ. ПРАВО. ОФИС',
            '14': 'КОМПЬЮТЕРЫ и IT',
            '15': 'ПРОИЗВОДСТВО. СТРОИТЕЛЬСТВО',
            '17': 'МАРКЕТИНГ. РЕКЛАМА',
            '18': 'ТОРГОВЛЯ',
            '19': 'ЛОГИСТИКА. СКЛАД',
            '20': 'ТРАНСПОРТ. АВТОБИЗНЕС',
            '21': 'МЕДИЦИНА. ФАРМАЦИЯ',
            '22': 'ОБРАЗОВАНИЕ. КУЛЬТУРА',
            '23': 'РЕСТОРАНЫ. ПИТАНИЕ',
            '24': 'ОХРАНА. ПОЛИЦИЯ',
            '25': 'УСЛУГИ',
            '26': 'РАБОТА ДЛЯ ВСЕХ',
            '27': 'СЕТЕВОЙ МАРКЕТИНГ',
            '30': 'ОБУЧЕНИЕ',
            '40': 'ПЕРСОНАЛ',
            '50': 'РАБОТА ВАХТОВЫМ МЕТОДОМ',
            '90': 'РАБОТА В МОСКВЕ',
            '0': 'БЕЗ РУБРИКИ'
            }

    """ ПОДГОТОВКА БД.
    -- Удаляем дубли по: профессии, контактному лицу, телефону.
    -- Удаляем без контактных данных.
    """
    
    query = conn.cursor()
    
    query.execute("DELETE FROM vacant WHERE ROWID NOT IN ("
        "SELECT MIN(ROWID) FROM vacant GROUP BY prof, face, phone);")

    query.execute("DELETE FROM vacant WHERE (phone = '') AND (email = '');")

    # Бан по id пользователя
    sql = ("DELETE FROM vacant WHERE ROWID IN "                                 
    "(SELECT v.ROWID FROM vacant as v, org as o WHERE v.id_user=o.id_user);")
    query.execute(sql)
    
    # Бан по id организации
    sql = ("DELETE FROM vacant WHERE ROWID IN "                                 
    "(SELECT v.ROWID FROM vacant as v, org as o WHERE v.id_org=o.id_org);")
    query.execute(sql)
    
    # ВЫГРУЗКА ПО НОМЕРАМ РУБРИКАМ
    for key in rub_dict:

        """ Если в рубрике нет вакансий, то переходим к следующей."""
        query.execute("SELECT count(*) FROM vacant WHERE rubr LIKE '{}%';"
            .format(key))
        rec = query.fetchone()
        count = rec[0]
        if count == 0:
            continue
        """ Название файла содержит: город, количество вакансий, название
        рубрики. Вывод в кодировке UTF-16 (InDesign)."""
        filname = 'outfile\\{} [{}] {}.txt'.format(
            window.sity.currentText(), count, rub_dict[key])
        f_out = open(filname,'w', encoding='utf16')

        """ Шапка - общее описание стилей."""
        f_out.write("""<UNICODE-WIN>
<Version:5><FeatureSet:InDesign-Roman><ColorTable:=<Black:COLOR:CMYK:Process:0,0,0,1>>
<DefineParaStyle:00 RUB\_SUPER=<Nextstyle:00 RUB\_SUPER><cTypeface:Bold><cSize:24.000000><cCase:All Caps><pHyphenationLadderLimit:0><cLeading:22.000000><pHyphenation:0><pHyphenationZone:14.149999><pSpaceAfter:2.849999><pTabRuler:28.350000381469727\,Left\,.\,0\,\;><cFont:Abbat><pDesiredWordSpace:0.900000><pMaxWordSpace:1.000000><pMinWordSpace:0.700000><pDesiredLetterspace:0.050000><pMaxLetterspace:0.300000><pMinLetterspace:-0.050000><pMinGlyphScale:0.500000><pKeepFirstNLines:1><pKeepLastNLines:1><pRuleAboveColor:None><pRuleAboveStroke:0.000000><pRuleAboveTint:100.000000><pRuleAboveOffset:16.700000><pRuleAboveRightIndent:337.299987><pRuleBelowColor:Black><pRuleBelowStroke:0.007812><pRuleBelowTint:100.000000><pRuleBelowOffset:1.142187><pRuleBelowRightIndent:337.299987><pRuleAboveOn:1><pTextAlignment:Center>>
<DefineParaStyle:03 STR VAKANS=<Nextstyle:03 STR VAKANS><cTypeface:Black><cSize:6.500000><cHorizontalScale:0.900000><pHyphenationLadderLimit:0><pAutoLeadPercent:1.800000><cLeading:6.500000><pHyphenation:0><pHyphenationZone:34.000000><pSpaceBefore:1.399999><pSpaceAfter:1.399999><pTabRuler:177.14999389648438\,Right\,.\,0\,\;><cFont:GoodPro><pDesiredWordSpace:0.900000><pMaxWordSpace:1.000000><pDesiredLetterspace:0.050000><pMaxLetterspace:0.150000><pMinGlyphScale:0.500000><pKeepWithNext:1><pKeepFirstNLines:1><pKeepLastNLines:1><pRuleAboveColor:None><pRuleAboveStroke:0.000000><pRuleAboveTint:100.000000><pRuleAboveOffset:5.650000><pRuleBelowColor:Black><pRuleBelowStroke:0.300000><pRuleBelowTint:30.000000><pRuleBelowOffset:1.699999><pRuleBelowOn:1>>
<DefineParaStyle:03 STR\_TEXT bold=<Nextstyle:03 STR\_TEXT bold><cTypeface:Book><cSize:6.300000><cLeading:6.615000><cFont:GoodPro><pMinGlyphScale:0.500000>>
<DefineParaStyle:03 STR\_TEXT=<Nextstyle:03 STR\_TEXT><cTypeface:Book><cSize:6.300000><pHyphenationLadderLimit:0><pAutoLeadPercent:1.800000><cLeading:6.500000><pHyphenationZone:11.350000><pTabRuler:161.5500030517578\,Center\,.\,0\,\;><cFont:GoodPro><pMaxWordSpace:1.200000><pMaxLetterspace:0.150000><pMinLetterspace:-0.150000><pMinGlyphScale:0.500000><pKeepFirstNLines:1><pKeepLastNLines:1><pRuleAboveColor:Black><pRuleAboveStroke:0.300000><pRuleAboveTint:30.000000><pRuleAboveOffset:4.250000><pRuleBelowColor:Black><pRuleBelowStroke:0.250000><pRuleBelowTint:100.000000><pTextAlignment:JustifyLeft>>
""")
        query.execute("SELECT prof, needs, salary, phone, email, face "
            "FROM vacant WHERE rubr LIKE '{}%' ORDER BY prof;".format(key))
        for val in query:

            # ДИНАМИЧЕСКОЕ ИЗМЕНЕНИЕ ИНФОРМАЦИИ
            """ Договорную зарплату сокращаем до "дог.". """
            salary = val[2].replace("договорная", "дог.")
            """Если нет телефона, то выводим электронную почту.  """
            contact = ''
            if val[3] != '':
                contact = 'Тел. ' +  val[3]
            else:
                contact = 'E-mail: ' +  val[4]
            """ Контактное лицо выводим в скобках."""
            face = ''
            if val[5] != '':
                face = '({})'.format(val[5])

            f_out.write('<ParaStyle:03 STR VAKANS><cTracking:1><cCase:All Caps>{} '
                    '<cTracking:><cCase:><cTypeface:Regular><cTracking:1><cCase:All Caps><cPosition:Superscript>	<cTypeface:><cTracking:><cCase:><cPosition:><cTracking:1>{}\n'
                    '<cTracking:><ParaStyle:03 STR\_TEXT><cTypeface:Regular>{} {} {}<cTypeface:><cTypeface:Regular><cSize:12.300000><cBaselineShift:-5.000000> *\n'
                    '<cTypeface:><cSize:><cBaselineShift:><ParaStyle:03 STR\_TEXT><cTypeface:Regular><cSize:12.300000><cBaselineShift:-5.000000>\n<cTypeface:><cSize:><cBaselineShift:>'
                    .format(val[0], salary, val[1], contact, face))
        f_out.close

    # БЕЗ РУБРИКИ
    filname = 'outfile\\{} ПРОФЕССИИ БЕЗ РУБРИКИ.txt'.format(window.sity.currentText())
    f_out = open(filname,'w')
    query.execute("SELECT prof FROM vacant WHERE rubr = 0 ORDER BY prof;")
    for val in query:
        #print(val['prof'])
        f_out.write('{}\n'.format(val['prof']))
    f_out.close

    conn.close
    btn_quit_click()


def btn_quit_click():
    """
    Закрыть программу.
    """

    def cookies_save(file_name):

        # СОХРАНЯЕМ КУКИ
        # Записываем в файл построчно.

        with open(file_name,'wb') as f:                                             # файл входной (сам закроется)
            allC = window.web.Сookies.allCookies()                                  # все куки
            for c in allC:                                                          # каждую куку
                f.write(c.toRawForm()+'\r\n')                                       # записываем построчно

    #
    cookies_save(cookies[window.sity.currentText()])
    conn.close()
    quit()


if __name__ == '__main__':                                                      # ОСНОВНОЙ ЦИКЛ
    main()
